﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace GeoSketch2.Core
{
    public partial class ImageRectificationForm :GeoSketchForm
    {
        #region Fields
        ImageRectification ImgRectification;

        /// <summary>
        /// The rectified image
        /// </summary>
        public GeoTaggedImage RectifiedImage;

        GeoTaggedImage InputImage;

        Layer LayerImage, LayerPoints, LayerHorizontalLines, LayerVerticalLines, LayerDistancesLines;

        #endregion
        
        #region Constructor
        /// <summary>
        /// The form for image rectification
        /// </summary>
        public ImageRectificationForm(Form MDIParentForm)
            :this(MDIParentForm,null)
        {
        }

        /// <summary>
        /// The form for image rectification
        /// </summary>
        public ImageRectificationForm(Form MDIParentForm, string ImageFullFileName)
            : base(Vars.Setup.Forms.ImageRectification.ActiveParentItems, MDIParentForm)
        {
            InitializeComponent();
            menuStrip_ImageRectification.Visible = false;
            Vars.Setup.DrawableObjects.Point2D.DrawId = true;

            LayerImage = new Layer("Image", Color.Black, new LineType(LineStyle.Solid), true,0);
            LayerPoints = new Layer("Points", Color.Red, new LineType(LineStyle.Solid), true,1);
            LayerHorizontalLines = new Layer("HorizontalLines", Color.Red, new LineType(LineStyle.Solid), true,2);
            LayerVerticalLines = new Layer("VerticalLines", Color.Blue, new LineType(LineStyle.Solid), true,3);
            LayerDistancesLines = new Layer("DistancesLines", Color.Lime, new LineType(LineStyle.Solid), true,4);

            geoDisplayBox.Viewport = new BaseViewport(geoDisplayBox);
            geoDisplayBox.Viewport.Layers.Clear();
            geoDisplayBox.Viewport.Layers.AddRange(new Layer[] { LayerImage, LayerPoints, LayerHorizontalLines, LayerVerticalLines, LayerDistancesLines });
            geoDisplayBox.Viewport.CurrentLayer = LayerImage;
            geoDisplayBox.Viewport.SortLayers();
            this.InputImage = new GeoTaggedImage(ImageFullFileName, LayerImage);

            SetupForm(toolbarsToolStripMenuItem);
            if (InputImage != null)
            {
                geoDisplayBox.Viewport.GeoObjects.Add(InputImage);
                geoDisplayBox.Viewport.CurrentObjectView = InputImage.ImageExtents.DeepClone();
            }

            this.TextBox_custom_cross_radius.TextChanged += new EventHandler(TextBox_custom_cross_radius_TextChanged);
            StatusStripLeftClicToolTextBox.KeyPress += new KeyPressEventHandler(StatusStripToolTextBox_KeyPress);
            StatusStripRightClicToolTextBox.KeyPress += new KeyPressEventHandler(StatusStripToolTextBox_KeyPress);
        }
        #endregion

        #region Items actions
        /// <summary>
        /// The method when clicking the help button
        /// </summary>
        public override void MDIParentHelp()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// The method when clicking the save button
        /// </summary>
        public override void MDIParentSave()
        {
            SaveRectifiedFile();
        }

        private void ToolStripMenuItem_Process_Click(object sender, EventArgs e)
        {
            ProcessImage();
        }

        private void MenuItem_Lines_Click(object sender, EventArgs e)
        {
            UncheckRectificationTechniques((ToolStripMenuItem)sender);
            MenuItem_Lines.Checked = !MenuItem_Lines.Checked;
        }

        private void MenuItem_Points_Click(object sender, EventArgs e)
        {
            UncheckRectificationTechniques((ToolStripMenuItem)sender);
            MenuItem_Points.Checked = !MenuItem_Points.Checked;
        }

        private void MenuItem_Cross_Click(object sender, EventArgs e)
        {
            UncheckRectificationTechniques((ToolStripMenuItem)sender);
            MenuItem_Cross.Checked = !MenuItem_Cross.Checked;
        }

        private void MenuItem_cross_blue_Click(object sender, EventArgs e)
        {
            UncheckCrossType((ToolStripMenuItem)sender);
            MenuItem_cross_blue.Checked = !MenuItem_cross_blue.Checked;
        }

        private void MenuItem_cross_red_Click(object sender, EventArgs e)
        {
            UncheckCrossType((ToolStripMenuItem)sender);
            MenuItem_cross_red.Checked = !MenuItem_cross_red.Checked;
        }

        private void MenuItem_cross_green_Click(object sender, EventArgs e)
        {
            UncheckCrossType((ToolStripMenuItem)sender);
            MenuItem_cross_green.Checked = !MenuItem_cross_green.Checked;
        }

        private void MenuItem_custom_cross_radius_Click(object sender, EventArgs e)
        {
            UncheckCrossType((ToolStripMenuItem)sender);
            MenuItem_custom_cross_radius.Checked = true;
        }

        void TextBox_custom_cross_radius_TextChanged(object sender, EventArgs e)
        {
            MenuItem_custom_cross_radius.Checked = true;
        }
        #endregion

        #region Methods
        private void ProcessImage()
        {
            if (MenuItem_Cross.Checked)
            {
                ProcessCross();
            }
            else if (MenuItem_Lines.Checked)
            {
                ProcessLines();
            }
            else if (MenuItem_Points.Checked)
            {
                ProcessPoints();
            }
            else if (MenuItem_Distances.Checked)
            {
                ProcessDistances();
            }
        }

        private void ProcessPoints()
        {
            List<Point2D> ImageCoordinates = new List<Point2D>();

            foreach (BaseDrawableObject obj in geoDisplayBox.Viewport.GeoObjects)
            {
                if (obj.GetType() == typeof(Point2D))
                {
                    ImageCoordinates.Add((Point2D)obj);
                }
            }
            int OutputImageSize;

            if (ComboBox_OutputImageSize.Text == "Auto")
            {
                OutputImageSize = (int)(new Point2D64D(InputImage.Image.Width, InputImage.Image.Height).Norm2D());
            }
            else
            {
                OutputImageSize = Convert.ToInt32(ComboBox_OutputImageSize.Text);
            }

            ObjectPointsInput OPI_Form = new ObjectPointsInput(ImageCoordinates.ToArray());
            DialogResult dr= OPI_Form.ShowDialog();

            if (dr == DialogResult.OK)
            {
                ImgRectification = new ImageRectification(InputImage.Image, OutputImageSize, OPI_Form.ImageCoordinates.InverseY(InputImage.Image.Height), OPI_Form.ObjectCoordinates);
                ImgRectification.ComputeTransformationCoefficients();
                RectifiedImage = ImgRectification.GetRectifiedImageGeoImage();

                DisplayRectifiedPicture();
            }
        }

        private void ProcessCross()
        {
            Point2D ClicCoordinates = new Point2D(new Point2D64D());
            double CrossRadius=0;

            foreach (BaseDrawableObject obj in geoDisplayBox.Viewport.GeoObjects)
            {
               if (obj.GetType() == typeof(Point2D))
                {
                    ClicCoordinates=(Point2D)obj;
                }
            }
            int OutputImageSize;

            if (ComboBox_OutputImageSize.Text == "Auto")
            {
                OutputImageSize = (int)(new Point2D64D(InputImage.Image.Width, InputImage.Image.Height).Norm2D());
            }
            else
            {
                OutputImageSize = Convert.ToInt32(ComboBox_OutputImageSize.Text);
            }

            if (MenuItem_cross_blue.Checked)
            {
                CrossRadius = Vars.Setup.StandardObjects.ImageRectification.BlueCrossRadius;
            } 
            else if (MenuItem_cross_red.Checked)
            {
                CrossRadius = Vars.Setup.StandardObjects.ImageRectification.RedCrossRadius;
            }
            else if (MenuItem_cross_green.Checked)
            {
                CrossRadius = Vars.Setup.StandardObjects.ImageRectification.GreenCrossRadius;
            }
            else if (MenuItem_custom_cross_radius.Checked)
            {
                CrossRadius = Convert.ToDouble(TextBox_custom_cross_radius.Text.Replace(",", "."), Vars.Setup.GeoSketch.NumberFormat);
            }
            else
            {
                MessageBox.Show("No cross size entered");
                return;
            }

            ImgRectification = new ImageRectification(InputImage.Image, OutputImageSize,(Point2D32S)InputImage.Object2ImageTransformation.Transform(ClicCoordinates.Point), CrossRadius);
            ImgRectification.ComputeTransformationCoefficients();

            foreach (Point2D64D point in ImgRectification.ImageCoordinates)
            {
                geoDisplayBox.Viewport.GeoObjects.Add(new Point2D(point.InverseY(InputImage.Image.Height),LayerPoints));
            }

            DialogResult ends_found= MessageBox.Show("Position OK?", "Cross ends found", MessageBoxButtons.YesNo);

            if (ends_found == DialogResult.Yes)
            {
                RectifiedImage = ImgRectification.GetRectifiedImageGeoImage();

                DisplayRectifiedPicture();
            }
            else
            {
                geoDisplayBox.Viewport.GeoObjects.Clear();
                geoDisplayBox.Viewport.GeoObjects.Add(InputImage);
            }
        }

        private void ProcessLines()
        {
            List<Line2D64D> HorizontalLines = new List<Line2D64D>();
            List<Line2D64D> VerticalLines = new List<Line2D64D>();
            List<Line2D64D> DistanceLines = new List<Line2D64D>();
            List<double> Distances = new List<double>();

            foreach (BaseDrawableObject obj in geoDisplayBox.Viewport.GeoObjects)
            {
                if (obj.GetType() == typeof(Polyline))
                {
                    if (obj.Layer == LayerHorizontalLines)
                    {
                        HorizontalLines.Add(new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position));
                    }
                    else if (obj.Layer == LayerVerticalLines)
                    {
                        VerticalLines.Add(new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position));
                    }
                    else if (obj.Layer == LayerDistancesLines)
                    {
                        DistanceLines.Add(new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position));
                        Distances.Add((double)obj.Tag);
                    }
                }
            }
            HorizontalLines.AddRange(VerticalLines);

            int OutputImageSize;

            if (ComboBox_OutputImageSize.Text == "Auto")
            {
                OutputImageSize = (int)(new Point2D64D(InputImage.Image.Width, InputImage.Image.Height).Norm2D());
            }
            else
            {
                OutputImageSize = Convert.ToInt32(ComboBox_OutputImageSize.Text);
            }

            ImgRectification = new ImageRectification(InputImage.Image, OutputImageSize, HorizontalLines.ToArray(), DistanceLines.ToArray(), Distances[0], Distances[1]);
            ImgRectification.ComputeTransformationCoefficients();
            RectifiedImage = ImgRectification.GetRectifiedImageGeoImage();

            DisplayRectifiedPicture();
        }

        private void UncheckRectificationTechniques(ToolStripMenuItem sender)
        {
            foreach (ToolStripMenuItem mi in Menu_RectificationTechnique.DropDownItems)
            {
                if (mi != sender)
                {
                    mi.Checked = false;
                }
            }
        }

        private void ProcessDistances()
        {
            Line2D64D HorizontalVerticalLine=null;
            List<Line2D64D> DistanceLines = new List<Line2D64D>();
            Line2D64D TempLine;

            foreach (BaseDrawableObject obj in geoDisplayBox.Viewport.GeoObjects)
            {
                if (obj.GetType() == typeof(Polyline))
                {
                    if (obj.Layer == LayerHorizontalLines)
                    {
                        HorizontalVerticalLine = new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position);
                        HorizontalVerticalLine.Tag = true;
                    }
                    else if (obj.Layer == LayerVerticalLines)
                    {
                        HorizontalVerticalLine = new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position);
                        HorizontalVerticalLine.Tag = false;
                    }
                    else if (obj.Layer == LayerDistancesLines)
                    {
                        TempLine = new Line2D64D(((Polyline)obj).Vertices[0].Position, ((Polyline)obj).Vertices[1].Position);
                        TempLine.Tag=(double)obj.Tag;
                        DistanceLines.Add(TempLine);
                    }
                }
            }

            int OutputImageSize;

            if (ComboBox_OutputImageSize.Text == "Auto")
            {
                OutputImageSize = (int)(new Point2D64D(InputImage.Image.Width, InputImage.Image.Height).Norm2D());
            }
            else
            {
                OutputImageSize = Convert.ToInt32(ComboBox_OutputImageSize.Text);
            }

            ImgRectification = new ImageRectification(InputImage.Image, OutputImageSize, DistanceLines.ToArray(), HorizontalVerticalLine);
            ImgRectification.ComputeTransformationCoefficients();
            RectifiedImage = ImgRectification.GetRectifiedImageGeoImage();

            DisplayRectifiedPicture();
        }

        private void DisplayRectifiedPicture()
        {
            DialogResult res = MessageBox.Show("Coefficients computation done! Display result image?", "Good", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
            if (res == DialogResult.Yes)
            {
                InputImage.Layer.Visible = false;
                geoDisplayBox.Viewport.Layers.Add(RectifiedImage.Layer);
                geoDisplayBox.Viewport.GeoObjects.Add(RectifiedImage);
                geoDisplayBox.Viewport.CurrentObjectView = RectifiedImage.Bounds.DeepClone<RectangleD>();
                geoDisplayBox.Refresh();
            }
        }

        private void UncheckCrossType(ToolStripMenuItem sender)
        {
            foreach (ToolStripMenuItem mi in MenuItem_cross_setup.DropDownItems)
            {
                if (mi != sender)
                {
                    mi.Checked = false;
                }
            }
        }

        private void SaveRectifiedFile()
        {
            RectifiedImage.FullFileName = Path.GetDirectoryName(InputImage.FullFileName) + "\\" + Path.GetFileNameWithoutExtension(InputImage.FullFileName) + "_rectified.png";
            RectifiedImage.Image.Save(RectifiedImage.FullFileName, System.Drawing.Imaging.ImageFormat.Png);
            RectifiedImage.WriteGSP();

            MessageBox.Show("Rectified image saved");
        }
        #endregion

        #region Status strip
        //Action when pressing the return key in a textbox of a tool
        void StatusStripToolTextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                ((ToolStripDropDownButton)((ToolStripTextBox)sender).OwnerItem).HideDropDown();
                ((BaseTool)((ToolStripTextBox)sender).Tag).TextEntry(((ToolStripTextBox)sender).Text);
                ((ToolStripTextBox)sender).Text = "";
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the label on the status bar to display messages
        /// </summary>
        public override ToolStripLabel StatusStripLabel
        {
            get
            {
                return Label_ToolsMessage;
            }
        }

        /// <summary>
        /// Gets the dropdown button on the status bar corresponding to the left clic tool 
        /// </summary>
        public override ToolStripDropDownItem StatusStripLeftClicToolDropDownButton
        {
            get
            {
                return _StatusStripLeftClicToolDropDown;
            }
        }

        /// <summary>
        /// Gets the textbox on the status bar corresponding to the left clic tool 
        /// </summary>
        public override ToolStripTextBox StatusStripLeftClicToolTextBox
        {
            get
            {
                return _StatusStripLeftClicToolTextBox;
            }
        }

        /// <summary>
        /// Gets the dropdown button on the status bar corresponding to the right clic tool 
        /// </summary>
        public override ToolStripDropDownItem StatusStripRightClicToolDropDownButton
        {
            get
            {
                return _StatusStripRightClicToolDropDown;
            }
        }

        /// <summary>
        /// Gets the textbox on the status bar corresponding to the right clic tool 
        /// </summary>
        public override ToolStripTextBox StatusStripRightClicToolTextBox
        {
            get
            {
                return _StatusStripRightClicToolTextBox;
            }
        } 
        #endregion

        private void MenuItem_Distances_Click(object sender, EventArgs e)
        {
            UncheckRectificationTechniques((ToolStripMenuItem)sender);
            MenuItem_Distances.Checked = !MenuItem_Distances.Checked;
        }
    }
}
